import { IAsyncResult, IDisposable } from '../../utils';
import { ConstructorOf } from '../../utils/declare';

/**
 * 该文件（`packages/core-common/src/event-bus/event-bus-types.ts`）定义了事件总线（EventBus）相关的类型和接口，主要用于标准化事件的发送、监听和异步处理。核心逻辑如下：
 *
 * 1. **事件选项类型**
 *     - `IEventFireOpts`：事件发送时的选项，目前支持 `nextTick`（是否下一个事件循环触发）。
 *     - `IAsyncEventFireOpts`：异步事件发送选项，支持设置 listener 的最大执行时长（`timeout`）。
 *
 * 2. **事件监听器类型**
 *     - `IEventListener<T>`：事件监听函数类型，接收事件对象。
 *
 * 3. **IEventBus 接口**
 *     - 统一定义事件总线的核心方法，包括：
 *         - `fire`：同步发送事件。
 *         - `fireAndAwait`：异步发送事件并收集所有监听器的结果。
 *         - `on`：注册事件监听器。
 *         - `once`：注册一次性事件监听器。
 *         - `onDirective`/`fireDirective`：通过字符串指令注册和触发事件，适合动态事件场景。
 *
 * 4. **IEventBus 标识符**
 *     - `IEventBus = Symbol('IEventBus')`：用于依赖注入标识。
 *
 * **总结**：
 * 本文件为事件总线的实现提供了标准接口和类型定义，便于系统内模块间以统一方式分发和监听事件，支持同步、异步和指令型事件。
 */
export interface IEventFireOpts {
  nextTick?: boolean;
}

export interface IAsyncEventFireOpts {
  /**
   * 异步事件发送时，listener的最大执行时长（listener并发执行)
   */
  timeout?: number;
}

export type IEventListener<T> = (target: T) => void;

export interface IEventBus {
  /**
   * 发出一个事件
   * Sample:
   class ResizeEvent extends BasicEvent<number> {}

   class LayoutStore {
   @Autowired(IEventBus)
    private eventBus: IEventBus;

    public fireResizeEvent() {
    const size = this.getSize();
    const resizeEvent = new ResizeEvent(size);
    this.eventBus.fire(resizeEvent);
    }

    // 不推荐，但是兼容 vscode 的 Event 设计
    public onDidResize(listener: (t: ResizeEvent) => void) {
    return this.eventBus.on(ResizeEvent, listener)
    }
    }
   */
  fire(target: any, opts?: IEventFireOpts): void;

  /**
   * 发送一个异步事件，等待并收集结果
   * @param e
   * @param opts
   */
  fireAndAwait<R>(
    e: any,
    opts?: IAsyncEventFireOpts
  ): Promise<IAsyncResult<R>[]>;

  /**
   * 监听 EventBus 中的事件
   * Sample:
   @Injectable()
    class FileTreeStore extends WitEventBus {
   @Autowired(IEventBus)
    private eventBus: IEventBus;

   @OnEvent(LayoutResize)
    public onLayoutResize(event: LayoutResize) {
    console.log(event.payload); // size number
    }
    }
   */
  on<T>(
    constructor: ConstructorOf<T>,
    listener: IEventListener<T>
  ): IDisposable;

  /**
   * 监听 EventBus 中的事件，只会触发一次
   */
  once<T>(
    constructor: ConstructorOf<T>,
    listener: IEventListener<T>
  ): IDisposable;

  onDirective<T>(directive: string, listener: IEventListener<T>): IDisposable;

  fireDirective(directive: string, payload?: any): void;
}
